package contract

import (
	"context"
	"errors"
	"raymond/global"

	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/core/types"
)

func ContractCall(contractFilename string, address string, method string, result *[]interface{}, params ...interface{}) error {
	if len(address) == 0 {
		return errors.New("address is nil")
	}
	ct, err := BuildContract(address, contractFilename)
	if err != nil {
		return err
	}
	var callOpts = &bind.CallOpts{
		Pending: true,
		Context: context.Background(),
	}
	return ct.Call(callOpts, result, method, params...)
}

func ContractTransact(contractFilename string, contractAddress string, method string, senderIdx uint, params ...interface{}) (*types.Transaction, error) {
	client := global.Client()
	if len(contractAddress) == 0 {
		return nil, errors.New("address is nil")
	}
	ct, err := BuildContract(contractAddress, contractFilename)
	if err != nil {
		return nil, err
	}
	auth, err := NewAuthByKeystore(senderIdx)
	if err != nil {
		return nil, err
	}
	gasPrice, err := client.SuggestGasPrice(context.Background())
	if err != nil {
		return nil, err
	}
	auth.GasPrice = gasPrice
	auth.GasLimit = 3000000
	return ct.Transact(auth, method, params...)
}

func ContractCallOnlyABIFile(contractFilename string, address string, method string, result *[]interface{}, params ...interface{}) error {
	if len(address) == 0 {
		return errors.New("address is nil")
	}
	ct, err := BuildContractOnlyABIFile(address, contractFilename)
	if err != nil {
		return err
	}
	var callOpts = &bind.CallOpts{
		Pending: true,
		Context: context.Background(),
	}
	return ct.Call(callOpts, result, method, params...)
}

func ContractTransactWithABIFileAndPr(contractFilename string, contractAddress string, method string, pr string, params ...interface{}) (*types.Transaction, error) {
	client := global.Client()
	if len(contractAddress) == 0 {
		return nil, errors.New("address is nil")
	}
	ct, err := BuildContractOnlyABIFile(contractAddress, contractFilename)
	if err != nil {
		return nil, err
	}
	auth, err := NewAuthByPrivatekey(pr)
	if err != nil {
		return nil, err
	}
	gasPrice, err := client.SuggestGasPrice(context.Background())
	if err != nil {
		return nil, err
	}
	auth.GasPrice = gasPrice
	auth.GasLimit = 100000
	return ct.Transact(auth, method, params...)
}

func ContractCallOnlyABI(content string, address string, method string, result *[]interface{}, params ...interface{}) error {
	if len(address) == 0 {
		return errors.New("address is nil")
	}
	ct, err := BuildContractOnlyABI(address, content)
	if err != nil {
		return err
	}
	var callOpts = &bind.CallOpts{
		Pending: true,
		Context: context.Background(),
	}
	return ct.Call(callOpts, result, method, params...)
}

func ContractTransactWithABIAndPr(content string, contractAddress string, method string, pr string, params ...interface{}) (*types.Transaction, error) {
	client := global.Client()
	if len(contractAddress) == 0 {
		return nil, errors.New("address is nil")
	}
	ct, err := BuildContractOnlyABI(contractAddress, content)
	if err != nil {
		return nil, err
	}
	auth, err := NewAuthByPrivatekey(pr)
	if err != nil {
		return nil, err
	}
	gasPrice, err := client.SuggestGasPrice(context.Background())
	if err != nil {
		return nil, err
	}
	auth.GasPrice = gasPrice
	auth.GasLimit = 100000
	return ct.Transact(auth, method, params...)
}
